/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package dale2507.gates.gate;

import dale2507.gates.GateDirectory;
import dale2507.gates.GatePlugin;
import dale2507.gates.Messenger;
import dale2507.gates.events.GateStatusChangeEvent;
import dale2507.gates.exceptions.GateConnectionException;
import dale2507.gates.exceptions.PermissionException;
import dale2507.gates.exceptions.VerificationException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.block.Block;
import org.bukkit.block.Sign;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockRedstoneEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.plugin.PluginManager;

/**
 *
 * @author Dale
 */
public final class Display implements Listener {
    
    private Gate gate;
    private Block block;
    
    /**
     * Creates a display gate component from a sign block
     * @param block The sign block to create the gate component from
     * @throws VerificationException Thrown if the block given doesn't contain a valid sign
     */
    public Display(Block block) throws VerificationException {
        this.block = block;
        if (this.block.getState() instanceof Sign) {
            Sign sign = this.getSign();
            
            if (this.getName().length() == 0) {
                this.setError();
                sign.setLine(1, Messenger.ERROR + "No Name");
                sign.update();
                throw new VerificationException("Display sign does not contain a name.");
            } else if (this.getName().contains("\\") || 
                    this.getName().contains("/") || 
                    this.getName().contains(":") || 
                    this.getName().contains("*") || 
                    this.getName().contains("?") || 
                    this.getName().contains("\"") || 
                    this.getName().contains("<") || 
                    this.getName().contains(">") || 
                    this.getName().contains("|")) {
                this.setError();
                sign.setLine(1, Messenger.ERROR + "Invalid Name");
                sign.setLine(2, "\\ / : * ? \" < > |");
                sign.update();
                throw new VerificationException("Display sign does not contain a name.");
            }
            sign.update();
        } else {
            throw new VerificationException("Display block does not contain a sign.");
        }
    }
    
    private Sign getSign() {
        return (Sign) this.block.getState();
    }
    
    void setGate(Gate gate) {
        this.gate = gate;
        this.getSign().setLine(0, Messenger.SUCCESS + "[Gate]");
        this.refreshStatus();
        
        PluginManager pm = Bukkit.getServer().getPluginManager();
        pm.registerEvents(this, GatePlugin.getInstance());
    }
    
    public Gate getGate() {
        return this.gate;
    }
    
    void setError() {
        this.setLineColor(0, Messenger.ERROR);
    }

    /**
     * Gets the block used to by the display
     * @return The block used by the display
     */
    public Block getBlock() {
        return block;
    }
    
    String getName() {
        return ChatColor.stripColor(this.getSign().getLine(1).replace(" ", "")).trim();
    }
    
    int getVisibility() {
        String vis = ChatColor.stripColor(this.getSign().getLine(2)).trim();
        if (vis.equalsIgnoreCase("hidden")) {
            return GateSettings.HIDDEN;
        } else if (vis.equalsIgnoreCase("private")) {
            return GateSettings.PRIVATE;
        } else if (!vis.equals("")) {
            this.setLineColor(2, ChatColor.RED);
        }
        return GateSettings.PUBLIC;
    }
    
    String getStatus() {
        return ChatColor.stripColor(this.getSign().getLine(3)).trim();
    }
    
    private void setStatus(Gate.Status status) {
        Sign sign = this.getSign();
        if (status == Gate.Status.RECEIVING || 
                status == Gate.Status.INCOMING || 
                status == Gate.Status.DISABLED || 
                status == Gate.Status.BROKEN) {
            sign.setLine(3, Messenger.ERROR + status.toString());
        } else if (status == Gate.Status.OUTGOING) {
            sign.setLine(3, Messenger.SUCCESS + status.toString());
        } else {
            sign.setLine(3, Messenger.INFO + status.toString());
        }
        sign.update();
    }
    
    void refreshStatus() {
        this.setStatus(this.getGate().getStatus());
    }
    
    private void setLineColor(int line, ChatColor color) {
        this.getSign().setLine(line, color + ChatColor.stripColor(this.getSign().getLine(line)));
    }
    
    @EventHandler(priority = EventPriority.LOW)
    public void onGateStatusChange(GateStatusChangeEvent event) {
        if (event.getGate().equals(this.getGate())) {
            setStatus(event.getNewStatus());
        }
    }
    
    @EventHandler(priority = EventPriority.HIGH)
    public void onSignHit(PlayerInteractEvent event) {
        if (event.getClickedBlock() != null && 
                event.getClickedBlock().equals(this.getBlock()) && 
                event.getAction() == Action.RIGHT_CLICK_BLOCK) {
            if (this.getGate() != null) {
                try {
                    if (this.getGate().getStatus() == Gate.Status.INACTIVE) {
                        try {
                            this.getGate().getActivator().activate(event.getPlayer());
                        } catch (GateConnectionException ex) {
                            Messenger.sendMessage(event.getPlayer(), Messenger.ERROR, ex.getMessage());
                        }
                    } else if (this.getGate().getStatus() == Gate.Status.DISABLED) {
                        Messenger.sendMessage(event.getPlayer(), Messenger.ERROR, "Source gate is disabled");
                    } else {
                        this.getGate().getActivator().deactivate(event.getPlayer());
                    }
                    event.setCancelled(true);
                } catch (PermissionException ex) {
                    Messenger.sendMessage(event.getPlayer(), Messenger.ERROR, ex.getMessage());
                }
            }
        }
    }
    
    @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
    public void onDisplayDestroyed(BlockBreakEvent event) {
        if (event.getBlock().equals(this.getBlock())) {
            GateDirectory.getInstance().deleteGate(this.getGate());
            if (event.getPlayer() != null) Messenger.sendMessage(event.getPlayer(), Messenger.SUCCESS, this.getGate().getSettings().getName() + " gate destroyed");
        }
    }
    
    @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
    public void onDisplayPowered(BlockRedstoneEvent event) {
        if (event.getBlock().equals(this.getBlock()) && event.getNewCurrent() > 0) {
            try {
                if (this.getGate() != null && this.getGate().getStatus() == Gate.Status.INACTIVE) {
                    try {
                        this.getGate().getActivator().activate(null);
                    } catch (GateConnectionException ex) {
                        Logger.getLogger(Display.class.getName()).log(Level.WARNING, ex.getMessage());
                    }
                } else {
                    this.getGate().getActivator().deactivate(null);
                }
            } catch (PermissionException ex) {
               Logger.getLogger(Display.class.getName()).log(Level.SEVERE, "", ex);
            }
        }
    }

    void removeListeners() {
        HandlerList.unregisterAll(this);
    }
    
}
